package com.charley.icloud.backup.controller;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.*;

import com.charley.icloud.backup.config.BackupDataSourceProperties;
import com.charley.icloud.backup.constants.BackupConstants;
import com.charley.icloud.backup.service.MysqlBackupService;
import com.charley.icloud.common.response.code.BackupSysCode;
import com.charley.icloud.common.response.code.HttpStatus;
import com.charley.icloud.common.response.result.HttpResponseResult;
import com.charley.icloud.common.response.result.HttpResponseResultFactory;
import com.charley.icloud.common.utils.FileUtils;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.enums.ParameterIn;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import org.springframework.http.ResponseEntity;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;

@RestController
@RequestMapping("/backup")
@Tag(name = "系统数据备份还原控制器", description = "系统数据备份还原控制器")
public class MySqlBackupController {

    @Resource
    MysqlBackupService mysqlBackupService;
    @Resource
    BackupDataSourceProperties properties;

    @GetMapping("/backup")
    @Operation(summary = "启动备份", description = "系统数据备份还原管理系统")
    public HttpResponseResult backup() {
        String backupFolderName = BackupConstants.DEFAULT_BACKUP_NAME + "_" + (new SimpleDateFormat(BackupConstants.DATE_FORMAT)).format(new Date());
        return backup(backupFolderName);
    }

    private HttpResponseResult backup(String backupFolderName) {
        String host = properties.getHost();
        String userName = properties.getUsername();
        String password = properties.getPassword();
        String database = properties.getDatabase();
        String backupFolderPath = BackupConstants.BACKUP_FOLDER + backupFolderName + File.separator;
        String fileName = database + "_" + BackupConstants.BACKUP_FILE_NAME;
        try {
            boolean backup = mysqlBackupService.backup(host, userName, password, backupFolderPath, fileName, database);
            if (!backup) {
                return HttpResponseResultFactory.fail(BackupSysCode.SYSTEM_BACKUP_ADD_FAIL, BackupSysCode.SYSTEM_BACKUP_ADD_FAIL_MSG);
            }
        } catch (Exception e) {
            return HttpResponseResultFactory.fail(HttpStatus.SC_INTERNAL_SERVER_ERROR, e.getMessage());
        }
        return HttpResponseResultFactory.buildHttpResponseResult(BackupSysCode.SYSTEM_BACKUP_ADD_SUCCESS, BackupSysCode.SYSTEM_BACKUP_ADD_SUCCESS_MSG);
    }

    @GetMapping("/restore")
    @Operation(summary = "恢复备份", description = "系统数据备份还原管理系统")
    @Parameter(name = "filename", description = "文件名称", required = true, in = ParameterIn.QUERY)
    public HttpResponseResult restore(@RequestParam String filename) {
        String host = properties.getHost();
        String userName = properties.getUsername();
        String password = properties.getPassword();
        String database = properties.getDatabase();
        String restoreFilePath = BackupConstants.RESTORE_FOLDER + filename;
        try {
            boolean restore = mysqlBackupService.restore(restoreFilePath, host, userName, password, database);
            if (!restore) {
                return HttpResponseResultFactory.fail(BackupSysCode.SYSTEM_BACKUP_RESTORE_FAIL, BackupSysCode.SYSTEM_BACKUP_RESTORE_FAIL_MSG);
            }
        } catch (Exception e) {
            return HttpResponseResultFactory.fail(HttpStatus.SC_INTERNAL_SERVER_ERROR, e.getMessage());
        }
        return HttpResponseResultFactory.buildHttpResponseResult(BackupSysCode.SYSTEM_BACKUP_RESTORE_SUCCESS, BackupSysCode.SYSTEM_BACKUP_RESTORE_SUCCESS_MSG);
    }

    @GetMapping("/findRecords")
    @Operation(summary = "备份记录列表", description = "系统数据备份还原管理系统")
    public HttpResponseResult findBackupRecords() {
        if (!new File(BackupConstants.DEFAULT_RESTORE_FILE).exists()) {
            // 初始默认备份文件
            backup(BackupConstants.DEFAULT_BACKUP_NAME);
        }
        List<Map<String, String>> backupRecords = new ArrayList<>();
        File restoreFolderFile = new File(BackupConstants.RESTORE_FOLDER);
        if (restoreFolderFile.exists()) {
            for (File file : Objects.requireNonNull(restoreFolderFile.listFiles())) {
                Map<String, String> backup = new HashMap<>();
                backup.put("name", file.getName());
                backup.put("title", file.getName());
                backup.put("path",restoreFolderFile.getName() + "/" + file.getName());
                if (BackupConstants.DEFAULT_BACKUP_NAME.equalsIgnoreCase(file.getName())) {
                    backup.put("title", "系统默认备份");
                }
                backupRecords.add(backup);
            }
        }
        // 排序，默认备份最前，然后按时间戳排序，新备份在前面
        backupRecords.sort(
                (o1, o2) -> BackupConstants.DEFAULT_BACKUP_NAME.equalsIgnoreCase(o1.get("name")) ? -1
                        : BackupConstants.DEFAULT_BACKUP_NAME.equalsIgnoreCase(o2.get("name")) ? 1 : o2.get("name").compareTo(o1.get("name"))
        );
        return HttpResponseResultFactory.success(backupRecords);
    }

    @GetMapping("/delete")
    @Operation(summary = "删除备份", description = "系统数据备份还原管理系统")
    @Parameter(name = "filename", description = "文件名称", required = true, in = ParameterIn.QUERY)
    public HttpResponseResult deleteBackupRecord(@RequestParam String filename) {
        if (BackupConstants.DEFAULT_BACKUP_NAME.equals(filename)) {
            return HttpResponseResultFactory.fail(BackupSysCode.SYSTEM_BACKUP_FILE_DELETE_FAIL_MSG, BackupSysCode.SYSTEM_BACKUP_FILE_DELETE_FAIL_MSG);
        }
        String restoreFilePath = BackupConstants.BACKUP_FOLDER + filename;
        try {
            FileUtils.deleteFile(new File(restoreFilePath));
        } catch (Exception e) {
            return HttpResponseResultFactory.fail(BackupSysCode.SYSTEM_BACKUP_FILE_DELETE_FAIL, e.getMessage());
        }
        return HttpResponseResultFactory.buildHttpResponseResult(BackupSysCode.SYSTEM_BACKUP_FILE_DELETE_SUCCESS, BackupSysCode.SYSTEM_BACKUP_FILE_DELETE_SUCCESS_MSG);
    }

    @GetMapping("/down")
    @Operation(summary = "备份文件下载", description = "系统数据备份还原管理系统")
    @Parameter(name = "filename", description = "文件名称", required = true, in = ParameterIn.QUERY)
    public ResponseEntity<byte[]> downRecords(@RequestParam String filename, HttpServletResponse response) {
        String fileSource = BackupConstants.RESTORE_FOLDER + filename;
        String sqlFile = "xxx.sql";
        File restoreFolderFile = new File(fileSource);
        if(restoreFolderFile.exists()){
            for (File file : Objects.requireNonNull(restoreFolderFile.listFiles())) {
                fileSource = fileSource + File.separator + file.getName();
                sqlFile = file.getName();
            }
        }
        File target = new File(fileSource);
        if(target.exists()){
            try {
                // ok表示http请求中状态码200
                ResponseEntity.BodyBuilder builder = ResponseEntity.ok();
                // 内容长度
                builder.contentLength(target.length());
                // application/octet-stream 二进制数据流（最常见的文件下载）
                builder.contentType(MediaType.APPLICATION_OCTET_STREAM);
                // 使用URLEncoding.decode对文件名进行解码
                builder.header("Access-Control-Expose-Headers", "Content-Disposition");
                builder.header("Content-Disposition", "attachment;filename="
                        .concat(String.valueOf(URLEncoder.encode(sqlFile, "UTF-8"))));

                return builder.body(org.apache.commons.io.FileUtils.readFileToByteArray(target));

            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        return null;
    }
}